package dongshi.daddy.needknow;

import org.junit.Assert;
import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.IntSummaryStatistics;
import java.util.List;
import java.util.function.IntBinaryOperator;
import java.util.stream.IntStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

public class IntStreamTest {

    public static void main(String[] args) throws Exception {
//        testGenerate();
//        testRange();
//        testOf();
//        testEmpty();
//        testBuilder();
//        testIterator();
//        testConcat();
//        testFilter();
//        testMap();
//        testMapObj();
//        testMapLong();
//        testAsLongStream();
//        testFlatMap();
//        testDistinct();
//        testSort();
//        testPeek();
//        testSkip();
//        testSortOrdered();
//        testReduce();
//        testReduce1();
//        testBoxed();
//        testCollect();
//        testMathOpt();
//        testMatchOpt();
        testFindOpt();
    }
    @Test
    public void testFindAny() {

    }
    private static void testFindOpt() {
        int findFirst = IntStream.of(4, 5, 5, 5).findFirst().getAsInt();
        System.out.println("findFirst: " + findFirst);
        int findAny = IntStream.of(42, 25, 52, 54).findAny().getAsInt();
        System.out.println("findAny: " + findAny);
    }

    private static void testMatchOpt() {
        boolean anyMatch = IntStream.of(-2, 2, -9, 10, 9).anyMatch(e -> e > 0);
//        Assert.assertTrue(result);
        System.out.println("anyMatch: " + anyMatch);
        boolean allMatch = IntStream.of(5, 5, 5, 5, 5).allMatch(e -> e > 0);
        System.out.println("allMatch: " + allMatch);
        boolean noneMatch = IntStream.of(4, 5, 5, 5).noneMatch(e -> e == 4);
        System.out.println("noneMatch: " + noneMatch);
    }

    private static void testMathOpt() {
        System.out.println("最大值：");
        System.out.println(IntStream.of(3, 90, 988, 1, 76).max().getAsInt());
        System.out.println("最小值：");
        System.out.println(IntStream.of(3, 90, 988, 1, 76).min().getAsInt());
        System.out.println("平均值：");
        System.out.println(IntStream.of(3, 90, 988, 1, 76).average().getAsDouble());
        System.out.println("元素个数：");
        System.out.println(IntStream.of(3, 90, 988, 1, 76).count());
        System.out.println("元素总和：");
        System.out.println(IntStream.of(3, 90, 988, 1, 76).sum());
        System.out.println("使用summaryStatistics进行数学运算：");
        IntSummaryStatistics summaryStatistics = IntStream.of(-2, 2, -9, 10, 9).summaryStatistics();
//        Assert.assertEquals(10, summaryStatistics.getSum());
        System.out.println("总和：" + summaryStatistics.getSum());
        System.out.println("最大值：" + summaryStatistics.getMax());
        System.out.println("最小值：" + summaryStatistics.getMin());
        System.out.println("元素个数：" + summaryStatistics.getCount());
        System.out.println("平均值：" + summaryStatistics.getAverage());
    }

    private static void testCollect() {
        // 需要提供容器工厂、元素收集器、容器组合器
        ArrayList<Integer> list = IntStream.range(0, 100).boxed().collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
        Assert.assertEquals(100, list.size());
    }

    private static void testBoxed() {
        IntStream.of(2, 7).boxed().forEach(v -> System.out.println(v + " -> " + v.getClass()));
    }

    private static void testReduce1() {
//        int[] arr = new int[] { 8, 90, 87, 43, 900, 12 };
//        int minVal = Integer.MAX_VALUE;
        // 获取最小值，执行过程如下：
        // Integer.min(left, right) -> Integer.min(8, 90) = 8
        // Integer.min(left, right) -> Integer.min(8, 7) = 7
        // Integer.min(left, right) -> Integer.min(7, 43) = 7
        // Integer.min(left, right) -> Integer.min(7, 5) = 5
        // Integer.min(left, right) -> Integer.min(5, 12) = 5 最终结果
        int minVal = IntStream.of(8, 90, 7, 43, 5, 12).reduce((left, right) -> {
            System.out.printf("left: %d, right: %d", left, right);
            System.out.println();
            return Integer.min(left, right);
        }).getAsInt();
        System.out.println("minVal: " + minVal);
    }

    private static void testReduce() {
        // 规约操作一定有值
        // 执行过程如下：
        // v1, v2 -> 0, 1 = 1
        // v1, v2 -> 1, 2 = 3
        // v1, v2 -> 3, 3 = 6
        // v1, v2 -> 6, 4 = 10
        // v1, v2 -> 10, 5 = 15
        // v1, v2 -> 15, 6 = 21
        // v1, v2 -> 21, 7 = 28
        // v1, v2 -> 28, 8 = 36
        // v1, v2 -> 36, 9 = 45 最终结果
        int sum = IntStream.range(0, 10).reduce(0, (v1, v2) -> v1 + v2);
        System.out.println("sum is: " + sum);
        // 相当于如下代码
        int result = 0;
        for (int i = 0; i < 10; i++) {
            result = result + i;
        }
        System.out.println("result is: " + result);
    }

    private static void testSortOrdered() {
        System.out.println("parallel 后顺序打乱");
        IntStream.of(1,5,-9,0,-5,2,5,8).parallel().forEach(System.out::println);
        System.out.println("parallel 后顺序保持不变");
        // 在并行遍历时，forEachOrdered将顺序遍历元素
        IntStream.of(1,5,-9,0,-5,2,5,8).parallel().forEachOrdered(System.out::println);
    }

    private static void testSkip() {
        IntStream.rangeClosed(1, 9).skip(6).forEach(System.out::println);
    }

    private static void testPeek() {
        IntStream.of(1, 2, 3, 4, 5)
//                .filter(e -> e >= 3)
                .peek(value -> System.out.printf("filter element: %d\n", value))
                .mapToObj(String::valueOf)
                .forEach(System.out::println);
    }

    private static void testSort() {
        IntStream.of(9, 80, 34, 2, 24).sorted().forEach(System.out::println);
    }

    private static void testDistinct() {
        IntStream.of(1, 2, 3, 3, 4, 2).distinct().forEach(System.out::println);
    }

    private static void testFlatMap() {
        // 这里根据上游的元素扩展出了更多的元素
        // 操作步骤如下：
        // 1：获取值1，执行IntStream.rangeClosed(0, 1)，生成0,1的IntStream
        // 2：获取值2，执行IntStream.rangeClosed(0, 2)，生成0,1,2的IntStream
        // 3：获取值3，执行IntStream.rangeClosed(0 3)，生成0,1,2,3的IntStream
        // 4：合并以上的3个IntStream，生成0,1,0,1,2,0,1,2,3的IntStream为最终结果
        IntStream.of(1, 2, 3).flatMap(e -> IntStream.rangeClosed(0, e)).forEach(System.out::println);
    }

    private static void testAsLongStream() {
        long[] longs = IntStream.rangeClosed(1, 10).asLongStream().toArray();
        for (long aLong : longs) {
            System.out.println(aLong);
        }
    }

    private static void testMapLong() {
        // 转换为*2的long值
        LongStream longStream = IntStream.rangeClosed(1, 5).mapToLong(v -> v * 2);
        longStream.forEach(v1 -> System.out.println(v1 + " -> " + ((Object)v1).getClass()));
    }

    private static void testMapObj() {
        Stream<String> stringStream = IntStream.rangeClosed(1, 5).mapToObj(value -> String.valueOf(value));
        stringStream.forEach(v -> System.out.println(v + "->" + v.getClass()));
    }

    private static void testMap() {
        IntStream originStream = IntStream.rangeClosed(1, 10);
        IntStream intStream = originStream.map(v -> v * 2);
        intStream.forEach(v -> System.out.println(v));
    }

    private static void testFilter() {
        // 过滤偶数
        IntStream.rangeClosed(1, 10).filter(value -> value % 2 == 0).forEach(v -> System.out.println(v));
    }

    private static void testConcat() {
        IntStream range = IntStream.range(1, 5);
        IntStream range1 = IntStream.rangeClosed(90, 95);
        IntStream concat = IntStream.concat(range, range1);
        concat.forEach(v -> System.out.println(v));
    }

    private static void testIterator() {
        // 第一个参数seed：初始值
        // 第二个参数IntUnaryOperator：用于根据当前元素生成下一个元素的类
        // 依次*2，生成下一个元素
        IntStream iterate = IntStream.iterate(1, operand -> operand * 2);
        // 限制10条，默认无限输出
        IntStream limit = iterate.limit(10);
        limit.forEach(v -> System.out.println(v));
    }

    private static void testBuilder() {
        IntStream.builder().add(90).add(87).build().forEach(v -> System.out.println(v));
    }

    private static void testEmpty() {
        int sum = IntStream.empty().sum();
        System.out.println(sum);
        System.out.println("---完美的分割线---");
        IntStream.empty().forEach(v -> System.out.println(v));
    }

    private static void testOf() {
        IntStream.of(9, 90, 876, 12).forEach(v -> System.out.println(v));
    }

    private static void testRange() {
        System.out.println("range: 左闭右开");
        IntStream.range(1, 5).forEach(value -> System.out.println(value));
        System.out.println("rangeClose: 左闭右闭");
        IntStream.rangeClosed(1, 5).forEach(value -> System.out.println(value));
    }
}
